#ifndef xpack_test_algo_addressing
#define xpack_test_algo_addressing
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::test_algo_addressing::inc
#include"test/helper.hpp" // 需要放第一
#include"algo/addressing.hpp"
#include"memop/fill.hpp"
#include"utils/counter.hpp"
#pragma pop_macro("xuser")

namespace mixc::test_algo_addressing{
    enum{
        buffer_length               = 32,
    };

    inline void free(auto pages, uxx length){
        for(uxx i = 0; i < length; i++){
            if (pages[i]){
                delete[] pages[i];
                pages[i]            = nullptr;
            }
        }
    }

    inline void fill_var(auto pages, uxx i_page_begin, uxx page_end){
        for(uxx i = i_page_begin, j = 1 << i_page_begin, k = j; i < page_end; i++){
            pages[i]                = (new uxx[k + 1/*多分配一个单位，避免多个 page 内存是连续的*/]);
            k                       = (j);
            j                      *= (2);
        }

        // 给每个页按顺序填充数值
        for(uxx i = 0, j = i_page_begin, k = j, i_page = i_page_begin; i_page < page_end; k = j, j++, i_page++){
            for(uxx l = 0, end = uxx(1) << k; l < end; i++, l++){
                pages[i_page][l]    = i;
            }
        }
    }

    xtest("addressing.var") {
        using namespace inc;
        uxxp pages[buffer_length]   = {};
        uxx  page_begin             = (0);
        uxx  page_end               = (16);
        uxx  page_mask              = ((1 << page_end) - 1) << page_begin;
        uxx  total_bytes            = (1 << (page_end - 1));

        fill_var(pages, page_begin, page_end);

        for(uxx i = 0; i < total_bytes; i++){
            auto guide              = addressing::var(page_mask, i);
            xassert_eq(pages[guide.page][guide.offset], i);
        }

        free(pages, buffer_length);

        page_begin                  = (1);
        page_end                    = (16);
        page_mask                   = ((1 << page_end) - 1) << page_begin;
        total_bytes                 = (1 << (page_end - 1));
        fill_var(pages, page_begin, page_end);

        for(uxx i = 0; i < total_bytes; i++){
            auto guide              = addressing::var(page_mask, i);
            xassert_eq(pages[guide.page][guide.offset], i);
        }

        free(pages, buffer_length);
    };

    inline void fill_fixed(auto pages, uxx mask){
        // 每读一次会自增
        inc::counter                counter;

        for(uxx i = sizeof(uxx) * 8 - 1; mask != 0; i--){
            if (uxx length = uxx(1) << i; mask & length){
                pages[i]            = new uxx[length + 1];
                mask               ^= length;
                inc::fill_with_operator(pages[i], counter, length);
            }
        }
    }

    xtest("addressing.fixed") {
        using namespace inc;

        uxxp pages[32]              = {};

        #define xgen(total_bytes)                                          \
        fill_fixed(pages, total_bytes);                                    \
                                                                           \
        for(uxx i = 0; i < total_bytes; i++){                              \
            auto guide              = addressing::fixed(total_bytes, i);   \
            xassert_eq(pages[guide.page][guide.offset], i);                \
        }                                                                  \
                                                                           \
        free(pages, buffer_length)

        xgen(1);
        xgen(2);
        xgen(3);
        xgen(4);
        xgen(5);
        xgen(6);
        xgen(7);
        xgen(8);
        xgen(9);
        xgen(10);
        xgen(11);
        xgen(12);
        xgen(13);
        xgen(14);
        xgen(15);
        xgen(16);
        #undef  xgen
    };
}

#endif
